#ifndef __M_QUEUE_H__
#define __M_QUEUE_H__

#include <iostream>
#include <string>
#include <unordered_map>
#include <memory>
#include <vector>
#include <mutex>
#include <sstream>
#include "../mqcommon/mq_msg.pb.h"
#include "../mqcommon/mq_loger.hpp"
#include "../mqcommon/mq_helper.hpp"

namespace mq{

//队列信息类
    struct MsgQueue{
        std::string name;
        bool durable;
        bool exclusive;
        bool auto_delete;
        google::protobuf::Map<std::string,std::string> args;

        MsgQueue(){}
        
        MsgQueue(const std::string& qname,bool qdurable,
            bool qexclusive,
            bool qauto_delete,
            const google::protobuf::Map<std::string,std::string>& qargs):name(qname),durable(qdurable),
            exclusive(qexclusive),args(qargs){}

        void setArgs(std::string str_args){
            //外部传递进来的格式字符串为：key=val&key=val....
            // 现在需要将key和val获取出来并加载到args中
            
            mqhelper::StrHelper splithepler;
            std::vector<std::string> res; 
            splithepler.split(str_args,"&",res);
            for(auto s : res)
            {
                //使用 find + substr 获取kv
                int pos = s.find('=',0);
                std::string key,val;
                key = s.substr(0,pos);
                val = s.substr(pos+1);

                //将 kv 插入到 map中
                // args.insert(std::make_pair(key,val));//使用make_pair将key插入
                args[key] = val;
            }
        }

        std::string getArgs(){
            std::string result;
            for(auto kv : args){
                result += kv.first + "=" + kv.second + "&";//直接变量args，并生成格式字符串返回出去
            } 
            return result;
        }
        //注意不要声明成：using ptr = std::shared_ptr<MsgQueue>(); 这样声明了一个对象了，此处只需要创建一个智能指针类型即可
        using ptr = std::shared_ptr<MsgQueue>;
    };

    //队列名 ： 队列指针
    using QueueMap = std::unordered_map<std::string,MsgQueue::ptr>;

    class MsgQueueMapper{
        private:
            mqhelper::SqliteHelper _sql_helper;//数据库句柄
        public:
            //声明 持久性管理 map 

        MsgQueueMapper(const std::string& dbfile):_sql_helper(dbfile){
            //1. 初始化数据库
            //2. 打开数据库
                //前提要确定路径中目录存在，文件不需要管因为即使没文件也会在打开时创建，而若没目录将出现大问题
            std::string parent =  mqhelper::FileHelper::parentDirectory(dbfile);
            if(parent != "./")//若不等于 ./ 的话表示有父级目录
            {
                mqhelper::FileHelper::createDirectory(parent); 
            }
            _sql_helper.open();
            // 3. 创建表(需要自己写)
            createTable();
        }

        //  std::string name;
        // bool durable;
        // bool exclusive;
        // bool auto_delete;
        // std::unordered_map<std::string,std::string> args;
        void createTable(){
            std::stringstream sql;
            sql << "create table if not exists queue_table(";
            sql << "name varchar(32) primary key, ";
            sql << "durable int, exclusive int, auto_delete int, ";
            sql << "args varchar(128));";
            assert(_sql_helper.exec(sql.str(),nullptr,nullptr));
        }


        void removeTable(){//直接删除表
            std::stringstream sql;
            sql << "drop table queue_table;";//DROP [TEMPORARY] TABLE [IF EXISTS] tbl_name [, tbl_name] ...
            assert(_sql_helper.exec(sql.str(),nullptr,nullptr));
        }


        bool insert(MsgQueue::ptr queue){
            std::stringstream sql;
            sql << "insert into queue_table values(";
            sql << "'" << queue->name << "', ";
            sql << queue->durable << ", ";
            sql << queue->exclusive << ", ";
            sql << queue->auto_delete << ", ";
            sql << "'" << queue->getArgs() << "' );";

            return _sql_helper.exec(sql.str(),nullptr,nullptr);
        }

        bool remove(const std::string& ename){
            std::stringstream sql;
            sql << "delete from queue_table where name = ";
            sql << "\'"<< ename  << "\';";
            return _sql_helper.exec(sql.str(),nullptr,nullptr);
        }

        QueueMap covery(){//恢复所有交换机，本质就是从数据库中查找出全部数据
            std::stringstream sql;
            sql << "select name,durable,exclusive,auto_delete,args from queue_table;";//select * form 表名;
            QueueMap result;
            _sql_helper.exec(sql.str(),&selecteCallback,&result);//将result传递进去进行插入操作，获取到底层查询到的数据
            return result;
        }

        private:
        // 1. void* 是外部传递进来的参数（通过强转使用）
        // 2. int 是一行中的数据列数
        // 3. 第一个char** 是储存每一行的字符指针数组
        // 4. 第二个char** 是存储每一列的字段名称
        static int selecteCallback(void* args,int num,char** row,char** col)//注意需要静态的，否则有this指针
        {
            //1. 强转参数args变回持久性队列管理 map 指针 
            QueueMap* result = (QueueMap*)args;
            // 创建临时的智能指针 空的 mqp 队列信息类
            MsgQueue::ptr mqp = std::make_shared<MsgQueue>();

            mqp->name = row[0]; 
            mqp->durable = (bool)std::stoi(row[1]);
            
            mqp->exclusive = (bool)std::stoi(row[2]);
            mqp->auto_delete = (bool)std::stoi(row[3]);
            mqp->setArgs(row[4]);
            
            //括号内填的是 Exchange 构造所需要的数据
            result->insert({mqp->name,mqp});//插入数据{交换机名，交换机}
            return 0;//表示正常
        }
    };

    class MsgQueueManager{
        public:
            using ptr = std::shared_ptr<MsgQueueManager>;

            MsgQueueManager(const std::string& dbfile):_mapper(dbfile){
                _msg_queues = _mapper.covery();
            }

        bool declareQueue(const std::string& qname,
            bool qdurable,
            bool qexclusive,
            bool qauto_delete,
            const google::protobuf::Map<std::string,std::string>& qargs){
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _msg_queues.find(qname);
                if(it != _msg_queues.end()){
                    return true;
                }
                //创建队列消息的智能指针
                MsgQueue::ptr tmp= std::make_shared<MsgQueue>();
                tmp->name = qname;
                tmp->durable = qdurable;
                tmp->exclusive = qexclusive;
                tmp->auto_delete = qauto_delete;
                tmp->args = qargs;

                if(qdurable){
                    //是否持久化
                    if(!_mapper.insert(tmp)){
                        //如果失败就进去，然后返回false
                        return false;
                    }
                }
                DLOG("创建队列成功，队列名为:%s",qname.c_str());
                _msg_queues.insert({qname,tmp});
                return true;
            }

            bool deleteQueue(const std::string& qname){
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _msg_queues.find(qname);
                if(it == _msg_queues.end()){//若果为空则表示不存在则直接返回
                    return false;
                }     
                if(it->second->durable){
                    //若有持久化则也删除
                    _mapper.remove(qname);
                }
                _msg_queues.erase(qname);
                return true;
            }
            
            MsgQueue::ptr selectQueue(const std::string& qname){
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _msg_queues.find(qname);
                if(it == _msg_queues.end()){//若果为空则表示不存在则直接返回
                    return MsgQueue::ptr();
                }   
                return it->second;
            }

            QueueMap AllQueue(){ // 此处后面的const是为了能让const MsgQueueManager对象也能调用该函数
                std::unique_lock<std::mutex> lock(_mutex);
                return _msg_queues;
            }

            bool exists(const std::string& qname){
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _msg_queues.find(qname);
                if(it == _msg_queues.end()){//若果为空则表示不存在则直接返回
                    return false;
                }   
                return true;
            }

            size_t size(){
                std::unique_lock<std::mutex> lock(_mutex);
                return _msg_queues.size();
            }

            void clear(){
                std::unique_lock<std::mutex> lock(_mutex);
                _mapper.removeTable();
                _msg_queues.clear();
            }
        private:
            std::mutex _mutex;
            QueueMap _msg_queues;
            MsgQueueMapper _mapper;
    };
}
#endif